package com.darwin.darwinBitmapEngine.map
{
	import com.darwin.darwinBitmapEngine.core.ContainerNode;
	import com.darwin.darwinBitmapEngine.core.INode;
	import com.darwin.darwinBitmapEngine.core.INodeList;
	import com.darwin.darwinBitmapEngine.core.NodeList;
	
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	/**
	 * 场景结构描述。CanvasMap对场景中的物件进行存储的和索引
	 * @author lipi
	 */
	public class CanvasMap
	{
		public function CanvasMap()
		{
			_nodeList = new NodeList();
			
			_nodeMap = new Dictionary();
			
			_oldRectDic = new Dictionary();
			
			_changeDic = new Dictionary();
		}
		
		
		//存储显示对象的列表 
		private var _nodeList:INodeList;
		
		//对地图进行索引 
		private var _nodeMap:Dictionary;
		
		//对地图的大小进行
		private var _gridWidth:int = 32;
		
		//记录的旧的对象位置
		private var _oldRectDic:Dictionary;
		
		//标记的对象改变列表
		private var _changeDic:Dictionary;
		
		
		/**
		 * 重置所有对象
		 */
		public function reset():void
		{
			_nodeList = new NodeList();
			_nodeMap = new Dictionary();
			_oldRectDic = new Dictionary();
			_changeDic = new Dictionary();
		}
		
		/**
		 * 返回画布的列表
		 */
		public function get nodeList():INodeList
		{
			return _nodeList;
		}
		
		/**
		 * 设置节点列表类型,即注入的类型
		 */
		public function setNodeListType(list:INodeList):void
		{
			_nodeList = list;
		}
		
		
		//添加节点到网格地图，这个方法将ContainerNode中的取出调用addToMap方法
		private function addNodeToMap(node:INode):void
		{
			var $sx:int;
			var $sy:int;
			var $ex:int;
			var $ey:int;
			var $w:int = 0;
			var $h:int = 0;
			if(node is ContainerNode)
			{
				var $containerNode:ContainerNode = (node as ContainerNode);
				for(var i:int = 0;i<$containerNode.numChildren;i++)
				{
					var $node:INode = $containerNode.getNodeAt(i);
					if($node.rect)
					{
						$w = $node.rect.width;
						$h = $node.rect.height;
					}else{
						$w = 0;
						$h = 0;
					}
					$sx = Math.floor(($node.x+$containerNode.x)/_gridWidth);
					$sy = Math.floor(($node.y+$containerNode.y)/_gridWidth);
					$ex = Math.ceil((($node.x+$containerNode.x)+$w)/_gridWidth);
					$ey = Math.ceil((($node.y+$containerNode.y)+$h)/_gridWidth);
					_oldRectDic[$node] = [$sx,$sy,$ex,$ey];
					addToMap($node,$sx,$sy,$ex,$ey);
				}
			}else{
				if(node.rect)
				{
					$w = node.rect.width;
					$h = node.rect.height;
				}else{
					$w = 0;
					$h = 0;
				}
				$sx = Math.floor(node.x/_gridWidth);
				$sy = Math.floor(node.y/_gridWidth);
				$ex = Math.ceil((node.x+$w)/_gridWidth);
				$ey = Math.ceil((node.y+$h)/_gridWidth);
				_oldRectDic[node] = [$sx,$sy,$ex,$ey];
				addToMap(node,$sx,$sy,$ex,$ey);
			}
		}
		
		//将节点添加到网格地图 
		private function addToMap(node:INode,sx:int,sy:int,ex:int,ey:int):void
		{
			for(var i:int = sx;i<ex;i++)
			{
				for(var j:int = sy;j<ey;j++)
				{
					if(_nodeMap[i] == null) _nodeMap[i] = new Dictionary();
					if(_nodeMap[i][j] == null) _nodeMap[i][j] = new Dictionary();
					
					_nodeMap[i][j][node] = true;
				}
			}
		}
		
		
		//将节点从网格地图中移除，这个方法将ContainerNode中的取出调用removeFromMap方法
		private function removeNodeFromMap(node:INode):void
		{
			var $sx:int;
			var $sy:int;
			var $ex:int;
			var $ey:int;
			var $oldRect:Array;
			if(node is ContainerNode)
			{
				var $containerNode:ContainerNode = (node as ContainerNode);
				for(var i:int = 0;i<$containerNode.numChildren;i++)
				{
					var $node:INode = $containerNode.getNodeAt(i);
					$oldRect = _oldRectDic[$node];
					delete _oldRectDic[$node];
					if($oldRect != null)
					{
						$sx = $oldRect[0];//Math.floor(($node.x+$containerNode.x)/_gridWidth);
						$sy = $oldRect[1];//Math.floor(($node.y+$containerNode.y)/_gridWidth);
						$ex = $oldRect[2];//Math.ceil((($node.x+$containerNode.x)+$node.rect.width)/_gridWidth);
						$ey = $oldRect[3];//Math.ceil((($node.y+$containerNode.y)+$node.rect.height)/_gridWidth);
						removeFromMap($node,$sx,$sy,$ex,$ey);
					}
				}
				delete _changeDic[node];
			}else{
				$oldRect = _oldRectDic[node];
				delete _oldRectDic[node];
				delete _changeDic[node];
				if($oldRect != null)
				{
					$sx = $oldRect[0];//Math.floor(node.x/_gridWidth);
					$sy = $oldRect[1];//Math.floor(node.y/_gridWidth);
					$ex = $oldRect[2];//Math.ceil((node.x+node.rect.width)/_gridWidth);
					$ey = $oldRect[3];//Math.ceil((node.y+node.rect.height)/_gridWidth);
					removeFromMap(node,$sx,$sy,$ex,$ey);
				}
			}
		}
		
		//将节点从网格地图中移除 
		private function removeFromMap(node:INode,sx:int,sy:int,ex:int,ey:int):void
		{
			for(var i:int = sx;i<ex;i++)
			{
				for(var j:int = sy;j<ey;j++)
				{
					if(_nodeMap[i] == null) _nodeMap[i] = new Dictionary();
					if(_nodeMap[i][j] == null) _nodeMap[i][j] = new Dictionary();
					delete _nodeMap[i][j][node];
				}
			}
		}
		
		
		
		public function get numChildren():int
		{
			return _nodeList.length;
		}
		
		/**
		 * 添加一个节点到map 
		 */
		public function addNode(node:INode):void
		{
			addNodeToMap(node);
			_nodeList.push(node);
		}
		
		/**
		 * 添加一个节点一个索引位置 
		 * @param node 节点对象
		 * @param index 索引
		 */
		public function addNodeAt(node:INode,index:int):void
		{
			addNodeToMap(node);
			_nodeList.splice(index,0,node);
		}
		
		/**
		 * 从map移除一个节点
		 */
		public function removeNode(node:INode):INode
		{
			removeNodeFromMap(node);
			var $length:int = _nodeList.length;
			for(var i:int = 0;i<$length;i++)
			{
				if(_nodeList.getNodeAt(i) == node)
				{
					_nodeList.splice(i,1);
					return node;
				}
			}
			return null;
		}
		
		
		/**
		 * 移除一个节点
		 * @param index 所在索引 
		 * @return 返回节点值
		 */
		public function removeNodeAt(index:int):INode
		{
			var $node:INode = _nodeList.getNodeAt(index);
			_nodeList.splice(index,1);
			removeNodeFromMap($node);
			return $node;
		}
		
		
		/**
		 * 取得位于某个索引中的节点
		 * @param index 索引值
		 * @return 返回某个索引的节点
		 */
		public function getNodeAt(index:int):INode
		{
			return _nodeList.getNodeAt(index);
		}
		
		
		/**
		 * 将状态(x,y,rect)被改变的对象做上标记存到字典
		 */
		public function addChangeNode(node:INode):INode
		{
			_changeDic[node] = node;
			return node;
		}
		
		//将状态改变的节点添加到实际位置
		private function addChangeNodeToMap():void
		{
			for(var item:Object in _changeDic)
			{
				this.removeNodeFromMap(item as INode);
				this.addNodeToMap(item as INode);
			}
		}
		
		
		//对节点进行排序
		private function sortNodeList(nodeDic:Dictionary):Vector.<INode>
		{
			var t:int = getTimer();
			var $leng:int = _nodeList.length;
			var $returnList:Vector.<INode> = new Vector.<INode>();
			for(var i:int = 0;i<$leng;i++)
			{
				if(_nodeList.getNodeAt(i) is ContainerNode)
				{
					var $parentNode:ContainerNode = _nodeList.getNodeAt(i) as ContainerNode;
					for(var j:int = 0;j<$parentNode.numChildren;j++)
					{
						if(nodeDic[$parentNode.getNodeAt(j)])
						{
							$returnList.push($parentNode.getNodeAt(j));
						}
					}
				}else{
					if(nodeDic[_nodeList.getNodeAt(i)])
					{
						$returnList.push(_nodeList.getNodeAt(i));
					}
				}
			}
			return $returnList;
		}
		
		private function dicItem(dic:Dictionary):Object
		{
			var $node:INode;
			var $count:int = 0;
			for(var item:Object in dic)
			{
				$node = item as INode;
				$count ++;
				if($count > 1) return -1;
			}
			return $node;
		}
		
		
		/** 
		 * 取得某一个坐标下物件列表 （在五百个显示列表下执行时间为0.2毫秒）
		 * @param x 画布x坐标 
		 * @param y 画布y坐标
		 * @return 返回点下的物件列表 
		 */
		public function getNodesForXY(x:Number,y:Number):Vector.<INode>
		{
			addChangeNodeToMap();
			var $sx:int = Math.floor(x/_gridWidth);
			var $sy:int = Math.floor(y/_gridWidth);
			
			if(_nodeMap[$sx] == null) return null;
			if(_nodeMap[$sx][$sy] == null) return null;
			var returnArr:Vector.<INode> = new Vector.<INode>();
			
			var $dic:Dictionary = _nodeMap[$sx][$sy];
			var $sortList:Vector.<INode> = sortNodeList($dic);
			var $returnVector:Vector.<INode> = new Vector.<INode>();
			
			
			for(var i:int = 0;i<$sortList.length;i++)
			{
				var $item:INode = $sortList[i];
				var $x:Number = x - $item.x;
				var $y:Number = y - $item.y;
				if($item.parentContainer is ContainerNode)
				{
					$x = x - ($item.x+($item.parentContainer as ContainerNode).x);
					$y = y - ($item.y+($item.parentContainer as ContainerNode).y);
				}else{
					$x = x - $item.x;
					$y = y - $item.y;
				}
				if($item.hitTest($x,$y))
				{
					returnArr.push($item);
				}
			}
			return returnArr;
		}
		
		
	}
}